home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / U-Z / VideoToolBox Folder / VideoToolboxSources / CopyBitsQuickly.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-23  |  11.3 KB  |  373 lines  |  [TEXT/KAHL]

  1. /*
  2. CopyBitsQuickly.c
  3.  
  4. CopyBitsQuickly.c is a dumb substitute for CopyBits that ignores the color
  5. tables and palettes and leaves the clut alone, simply copying the raw pixels
  6. without any translation. It's for doing animations. (Try the demo Sandstorm.)
  7. Besides copying images, it can also add or multiply them. At one time it copied
  8. much faster than CopyBits did, but the latest timing (under System 7.01), by
  9. TimeVideo, indicates that they are of equal speed.
  10.  
  11. Apple's CopyBits is an Apple Macintosh Toolbox routine for copying images, and
  12. is documented in Inside Macintosh Volumes I,V, and VI. Unlike CopyBits,
  13. CopyBitsQuickly does not cause the Memory Manager to move memory, and thus may
  14. be used in a VBL task.
  15.  
  16. The returned value is nonzero if an error occurred.
  17.  
  18. CopyBitsQuickly supports three modes:
  19.  
  20. srcCopy causes the source to be copied to the destination.
  21.  
  22. addOver causes the source and destination to be added together. Both must have 
  23. 8-bit pixels.  Overflow is ignored.
  24.  
  25. mulOver causes the source and destination to be multiplied, pixel by
  26. pixel. Both must have 8-bit pixels. After multiplication, the product is divided
  27. by 128 and stored in the destination. Overflow is ignored. All the arithmetic
  28. is unsigned.
  29.  
  30. RESTRICTIONS:
  31. It insists that srcBits and dstBits both have the same number of bits/pixel.
  32. It insists that dstRect be the same size as srcRect
  33. It insists that mode==srcCopy, addOver, or new multiplyQuickly.
  34. It insists that maskRgn==NULL
  35. If a Rect extends across multiple screens only as much of the upper-left of the
  36. Rect that's on one device will be used. The rest is clipped off.
  37. If mode is addOver or mulOver then the pixel size must be 8 bits, in both
  38. source and destination.
  39.  
  40. If CopyBitsQuickly detects a violation of any of these restrictions it will return
  41. a nonzero value, indicating that an error occured.
  42.  
  43. NOTE: For highest speed you should choose your srcRectPtr & dstRectPtr so that the
  44. first point moved to and from each row begins at a memory address that is a multiple
  45. of 4 bytes. The effect on speed is substantial, about 25%. 
  46.  
  47. NOTE: If your computer boots in 24-bit mode, as set by the Memory Control Panel,
  48. then the THINK C Debugger will crash if it's activated while you've temporarily
  49. switched into 32-bit mode. So don't put any breakpoints in the section of the
  50. code bracketed by calls to SwapMMUMode() unless your computer booted up in
  51. 32-bit mode. If your computer boots in 32-bit mode then the calls to SwapMMUMode
  52. do nothing, and you can put Debugger breakpoints anywhere.
  53.  
  54. Copyright ©1989-1993 Denis G. Pelli. 
  55.  
  56. HISTORY:
  57. 1/89 dgp    Version 2.0: added support for PixMaps and multiple screens. Added checking.
  58. 6/89 dgp    Version 3.0: now use RectToAddress, which clips to one device.
  59. 10/89 dgp    Version 3.5: Improved resolution from longs to bytes.
  60. 10/89 dgp    Version 4.0: Added new mode: addOver
  61. 3/90  dgp    Version 4.01: Made cosmetic changes:
  62.             renamed srcRect & dstRect to srcRectPtr and dstRectPtr.
  63.             renamed srcAdd to addOver, to conform to CopyBits.
  64.             added a few more comments to explain the initial clipping.
  65. 3/20/90    dgp    made compatible with MPW C.
  66. 4/20/90    dgp    now uses 32-bit addressing only if QD32 is present.
  67. 4/9/91    dgp    v 4.05: changed nudge from short to long, just to be safe
  68. 8/24/91    dgp    Made compatible with THINK C 5.0.
  69. 4/15/92    dgp    Updated CopyBitsQuickly's function header to ANSI style.
  70. 10/5/92 dgp    Dropped support for THINK C 4. Updated the documentation above.
  71. 12/2/92 dgp cosmetic changes
  72. 12/8/92 dgp fixed major gaffe introduced on 12/2/92: "case" prefix was 
  73.             missing in switch statement. This caused CopyBitsQuickly to do nothing. 
  74. 1/31/93    dgp    Added new "multiplyQuickly" mode requested by Josh Solomon. Now 
  75.             insist on 8-bit pixels for both addOver and multiplyQuickly modes.
  76. 2/18/93    js    added mulOver to list of allowed modes. (Oops! - dgp.) Works ok now.
  77. 2/18/93    dgp    Now return int, nonzero if error occurred.
  78. */
  79. #include "VideoToolbox.h"
  80.  
  81. typedef unsigned char *UPtr;
  82.  
  83. static void srcCopyQuickly(UPtr Src,unsigned short srcinc,
  84.     UPtr Dst,unsigned short dstinc,
  85.     unsigned long bytes,unsigned long lines);
  86. static void addOverQuickly(UPtr Src,unsigned short srcinc,
  87.     UPtr Dst,unsigned short dstinc,
  88.     unsigned long bytes,unsigned long lines);
  89. static void mulOverQuickly(register UPtr Src,register unsigned short srcinc,
  90.     register UPtr Dst,register unsigned short dstinc,
  91.     unsigned long bytes,unsigned long lines);
  92.  
  93. typedef union {
  94.     unsigned long *L;
  95.     unsigned short *W;
  96.     unsigned char *B;
  97. } unsignedPtr;
  98.  
  99. int CopyBitsQuickly(BitMap *srcBits,BitMap *dstBits
  100.     ,Rect *srcRectPtr,Rect *dstRectPtr,int srcMode,RgnHandle maskRgn)
  101. {
  102.     UPtr Src,Dst;
  103.     unsigned short srcinc,dstinc;
  104.     unsigned long lines;
  105.     short srcRowBytes,dstRowBytes;
  106.     short srcPixelSize,dstPixelSize;
  107.     short srcBitsOffset,dstBitsOffset;
  108.     Rect mySrcRect,myDstRect;
  109.     int dx,dy;
  110.     long nudge;
  111.     long bytes;
  112.  
  113.     if(srcMode != srcCopy && srcMode != addOver && srcMode != mulOver) return 1;
  114.     if(maskRgn != NULL) return 1;
  115.  
  116.     /* clip the rect to be copied by the bounds of source and destination */
  117.     mySrcRect=*srcRectPtr;
  118.     myDstRect=*dstRectPtr;
  119.     /* first make sure that srcRect and dstRect are the same size */
  120.     if(mySrcRect.bottom-mySrcRect.top != myDstRect.bottom-myDstRect.top || 
  121.         mySrcRect.right-mySrcRect.left != myDstRect.right-myDstRect.left) 
  122.             return 2;
  123.     dx=myDstRect.left-mySrcRect.left;
  124.     dy=myDstRect.top-mySrcRect.top;
  125.     /* clip myDstRect */
  126.     Dst = RectToAddress((PixMap *)dstBits,&myDstRect,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  127.  
  128.     /*
  129.     This prevents writing outside the destination.
  130.     The cost is that part of the inside will not be written.
  131.     The problem arises because this routine's code can only write whole bytes,
  132.     and the boundary may be in the middle of a byte. So, rather than writing an
  133.     extra fraction of a byte (outside the destination rect) we leave the byte
  134.     alone and fail to update a small portion inside the destination rect.
  135.     */
  136.     if(dstBitsOffset>0) {
  137.         nudge=(7+dstBitsOffset)/8;
  138.         dstBitsOffset -= nudge*8;
  139.         Dst += nudge;
  140.         myDstRect.left += nudge*8/dstPixelSize;
  141.     }
  142.  
  143.     /* Copy any clipping of myDstRect over to mySrcRect */
  144.     mySrcRect=myDstRect;
  145.     OffsetRect(&mySrcRect,-dx,-dy);
  146.     /* clip mySrcRect */
  147.     Src = RectToAddress((PixMap *)srcBits,&mySrcRect
  148.         ,&srcRowBytes,&srcPixelSize,&srcBitsOffset);
  149.     /* Copy any clipping of mySrcRect back to myDstRect */
  150.     myDstRect=mySrcRect;
  151.     OffsetRect(&myDstRect,dx,dy);
  152.  
  153.     Dst = RectToAddress((PixMap *)dstBits,&myDstRect
  154.         ,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  155.     if(Src==NULL || Dst==NULL) return 3;
  156.     if(srcPixelSize != dstPixelSize) return 4;
  157.     bytes = mySrcRect.right - mySrcRect.left;    /* number of pixels per line */
  158.     bytes *= srcPixelSize;                        /* number of bits per line */
  159.     bytes /= 8;                                    /* number of bytes per line */
  160.     srcinc = srcRowBytes - bytes;        /* offset in bytes to beginning of next line */
  161.     dstinc = dstRowBytes - bytes;
  162.     lines=mySrcRect.bottom - mySrcRect.top;        /* number of lines */
  163.     switch(srcMode){
  164.     case srcCopy:
  165.         srcCopyQuickly(Src,srcinc,Dst,dstinc,bytes,lines);
  166.         break;
  167.     case addOver:
  168.         if(srcPixelSize!=8)return 5;
  169.         addOverQuickly(Src,srcinc,Dst,dstinc,bytes,lines);
  170.         break;
  171.     case mulOver:
  172.         if(srcPixelSize!=8)return 5;
  173.         mulOverQuickly(Src,srcinc,Dst,dstinc,bytes,lines);
  174.         break;
  175.     default:
  176.         break;
  177.     }
  178.     return 0;
  179. }
  180.  
  181.     
  182. static void srcCopyQuickly(UPtr xSrc,unsigned short xsrcinc,
  183.     UPtr xDst,unsigned short xdstinc,
  184.     unsigned long bytes,unsigned long lines)
  185. {
  186.     register unsignedPtr Src,Dst;/* alas, THINK C refuses to place these in registers */
  187.     #if THINK_C
  188.         register unsigned long *SrcR,*DstR;
  189.     #endif
  190.     register unsigned short i,j=lines,longs,srcinc=xsrcinc,dstinc=xdstinc;
  191.     short extra,extra8,extra16;
  192.     char mmumode;
  193.     Boolean qD32Exists=QD32Exists();
  194.     
  195.     Src.B=xSrc;
  196.     Dst.B=xDst;
  197.     #if THINK_C
  198.         SrcR=Src.L;
  199.         DstR=Dst.L;
  200.     #endif
  201.     longs = bytes/sizeof(long);                    /* number of longs per line */
  202.     extra = bytes - longs*sizeof(long);            /* residue */
  203.     extra16=extra8=FALSE;
  204.     if(extra >= sizeof(short)) {
  205.         extra16=TRUE;
  206.         extra -= sizeof(short);
  207.     }
  208.     if(extra >= 1) {
  209.         extra8=TRUE;
  210.         extra--;
  211.     }
  212.     mmumode=true32b;
  213.     if(qD32Exists)SwapMMUMode(&mmumode);    /* set 32-bit mode */
  214.     /* now choose the fastest possible loop */
  215.     if(srcinc != 0 || dstinc !=0 || extra16 || extra8) {
  216.         #if !THINK_C
  217.             for(;j>0;j--) {
  218.                 for(i=longs;i>0;i--) *Dst.L++ = *Src.L++;
  219.                 if(extra16) *Dst.W++ = *Src.W++;
  220.                 if(extra8) *Dst.B++ = *Src.B++;
  221.                 Src.B += srcinc;
  222.                 Dst.B += dstinc;
  223.             }
  224.         #else
  225.             goto rows1;
  226.     row1:        i=longs;
  227.                 goto cols1;
  228.             asm {
  229.     col1:        MOVE.L    (SrcR)+,(DstR)+
  230.     cols1:        DBRA    i,@col1
  231.             }
  232.                 if(extra16)    asm {MOVE.W    (SrcR)+,(DstR)+};
  233.                 if(extra8)    asm {MOVE.B    (SrcR)+,(DstR)+};
  234.             asm {
  235.                 ADDA.W    srcinc,SrcR
  236.                 ADDA.W    dstinc,DstR
  237.     rows1:        DBRA    j,@row1
  238.             }
  239.         #endif
  240.         if(qD32Exists)SwapMMUMode(&mmumode);    /* restore */
  241.         return;
  242.     }
  243.     if(longs*(long)j > 0x10000L) { /* DBRA only uses the lower 16 bits */
  244.         #if !THINK_C
  245.             for(;j>0;j--) {
  246.                 for(i=longs;i>0;i--) *Dst.L++ = *Src.L++;
  247.             }
  248.         #else
  249.             goto rows3;
  250.     row3:        i=longs;
  251.                 goto cols3;
  252.             asm {
  253.     col3:        MOVE.L    (SrcR)+,(DstR)+
  254.     cols3:        DBRA    i,@col3
  255.             }
  256.             asm {
  257.     rows3:    DBRA    j,@row3
  258.             }
  259.         #endif
  260.         if(qD32Exists)SwapMMUMode(&mmumode);    /* restore */
  261.         return;
  262.     }
  263.     else {
  264.         j *= longs;
  265.         #if !THINK_C
  266.             for(;j>0;j--) *Dst.L++ = *Src.L++;
  267.         #else
  268.             goto cols4;
  269.             asm {
  270.     col4:        MOVE.L    (SrcR)+,(DstR)+
  271.     cols4:        DBRA    j,@col4
  272.             }
  273.         #endif
  274.         if(qD32Exists)SwapMMUMode(&mmumode);    /* restore */
  275.         return;
  276.     }
  277. }
  278.  
  279. static void addOverQuickly(UPtr xSrc,unsigned short xsrcinc,
  280.     UPtr xDst,unsigned short xdstinc,
  281.     unsigned long xbytes,unsigned long lines)
  282. {
  283.     register UPtr Src=xSrc,Dst=xDst;
  284.     register unsigned long i,j=lines,bytes=xbytes,srcinc=xsrcinc,dstinc=xdstinc;
  285.     char mmumode;
  286.     Boolean qD32Exists=QD32Exists();
  287.     
  288.     mmumode=true32b;
  289.     if(qD32Exists)SwapMMUMode(&mmumode);    /* set 32-bit mode */
  290.  
  291.     /* now choose the fastest possible loop */
  292.     if(srcinc != 0 || dstinc !=0) {
  293.         #if !THINK_C
  294.             for(;j>0;j--) {
  295.                 for(i=bytes;i>0;i--) *Dst++ += *Src++;
  296.                 Src += srcinc;
  297.                 Dst += dstinc;
  298.             }
  299.         #else
  300.             goto rows1;
  301.     row1:        i=bytes;
  302.                 goto cols1;
  303.             asm {
  304.     col1:        MOVE.B    (Src)+,D0
  305.                 ADD.B    D0,(Dst)+
  306.     cols1:        DBRA    i,@col1
  307.                 ADDA.W    srcinc,Src
  308.                 ADDA.W    dstinc,Dst
  309.     rows1:    DBRA    j,@row1
  310.             }
  311.         #endif
  312.         if(qD32Exists)SwapMMUMode(&mmumode);    /* restore */
  313.         return;
  314.     }
  315.     if(bytes*(long)j > 0x10000L) { /* the DBRA only uses the lower 16 bits */
  316.         #if !THINK_C
  317.             for(;j>0;j--) {
  318.                 for(i=bytes;i>0;i--) *Dst++ += *Src++;
  319.             }
  320.         #else
  321.             goto rows3;
  322.     row3:        i=bytes;
  323.                 goto cols3;
  324.             asm {
  325.     col3:        MOVE.B    (Src)+,D0
  326.                 ADD.B    D0,(Dst)+
  327.     cols3:        DBRA    i,@col3
  328.     rows3:    DBRA    j,@row3
  329.             }
  330.         #endif
  331.         if(qD32Exists)SwapMMUMode(&mmumode);    /* restore */
  332.         return;
  333.     }
  334.     else {
  335.         j *= bytes;
  336.         #if !THINK_C
  337.             for(;j>0;j--) *Dst++ += *Src++;
  338.         #else
  339.             goto cols4;
  340.             asm {
  341.     col4:        MOVE.B    (Src)+,D0
  342.                 ADD.B    D0,(Dst)+
  343.     cols4:        DBRA    j,@col4
  344.             }
  345.         #endif
  346.         if(qD32Exists)SwapMMUMode(&mmumode);    /* restore */
  347.         return;
  348.     }
  349. }
  350.  
  351. // Multiply two unsigned 8-bit pixels, and divide the product by 128.
  352. static void mulOverQuickly(register UPtr Src,register unsigned short srcinc,
  353.     register UPtr Dst,register unsigned short dstinc,
  354.     unsigned long bytes,unsigned long lines)
  355. {
  356.     register unsigned long i,j;
  357.     char mmumode;
  358.     Boolean qD32Exists=QD32Exists();
  359.     
  360.     mmumode=true32b;
  361.     if(qD32Exists)SwapMMUMode(&mmumode);    /* set 32-bit mode */
  362.     for(j=lines;j>0;j--) {
  363.         for(i=bytes;i>0;i--) {
  364.             *Dst = (unsigned char)((unsigned short)(*Dst)*(unsigned short)(*Src)>>7);
  365.             Src++;
  366.             Dst++;
  367.         }
  368.         Src += srcinc;
  369.         Dst += dstinc;
  370.     }
  371.     if(qD32Exists)SwapMMUMode(&mmumode);    /* restore */
  372. }
  373.